#include <string.h>

#include "functions.h"
#include "macros.h"

#include <stdio.h>
_OPCFun tavm_run_exec[] =
{
    &EF_Debug,
    &EF_Get,
    &EF_Add,
    &EF_Sub,
    &EF_Mul,
    &EF_Muli,
    &EF_Div,
    &EF_Divi,
    &EF_LHead,
    &EF_LTail,
    &EF_LLink,
    &EF_LAdd
};

void EF_Debug(struct Agent_Var* agent)
{
    char* txt = (char*)(agent->pc + tavm_tables[TID_CODE].start);
    OFFSET(agent,strlen(txt)+1);

    printf(txt);
}

void EF_Get(struct Agent_Var* agent)
{
    struct DataEntry* de_ret = readDataEntry(agent);
    struct DataEntry* de_var2 = readDataEntry(agent);

    MEMCPYE(de_ret,de_var2,tavm_data_type_size[de_ret->type]);
}

void EF_Add(struct Agent_Var* agent)
{
    struct DataEntry* de_ret = readDataEntry(agent);
    struct DataEntry* de_var1 = readDataEntry(agent);
    struct DataEntry* de_var2 = readDataEntry(agent);

    uint16 val1 = GETE(de_var1,uint16);
    uint16 val2 = GETE(de_var2,uint16);

    uint16 ret = val1 + val2;

    PUTE(de_ret,ret,uint16);

    printf("dodano %d\n", val2);

}


void EF_Sub(struct Agent_Var* agent)
{
    struct DataEntry* de_ret = readDataEntry(agent);
    struct DataEntry* de_var1 = readDataEntry(agent);
    struct DataEntry* de_var2 = readDataEntry(agent);

    uint16 val1 = GETE(de_var1,uint16);
    uint16 val2 = GETE(de_var2,uint16);

    uint16 ret = val1 - val2;

    PUTE(de_ret,ret,uint16);

   // printf("odejto %d\n", val2);
}


void EF_Mul(struct Agent_Var* agent)
{
    struct DataEntry* de_ret = readDataEntry(agent);
    struct DataEntry* de_var1 = readDataEntry(agent);
    struct DataEntry* de_var2 = readDataEntry(agent);

    uint16 val1 = GETE(de_var1,uint16);
    uint16 val2 = GETE(de_var2,uint16);

    uint16 ret = val1 * val2;

    PUTE(de_ret,ret,uint16);
}

void EF_Muli(struct Agent_Var* agent)
{
    struct DataEntry* de_ret = readDataEntry(agent);
    struct DataEntry* de_var1 = readDataEntry(agent);
    struct DataEntry* de_var2 = readDataEntry(agent);

    int16 val1 = GETE(de_var1,int16);
    int16 val2 = GETE(de_var2,int16);

    int16 ret = val1 * val2;

    PUTE(de_ret,ret,int16);
}

void EF_Div(struct Agent_Var* agent)
{
    struct DataEntry* de_ret = readDataEntry(agent);
    struct DataEntry* de_var1 = readDataEntry(agent);
    struct DataEntry* de_var2 = readDataEntry(agent);

    uint16 val1 = GETE(de_var1,uint16);
    uint16 val2 = GETE(de_var2,uint16);

    uint16 ret = val1 / val2;

    PUTE(de_ret,ret,uint16);
}

void EF_Divi(struct Agent_Var* agent)
{
    struct DataEntry* de_ret = readDataEntry(agent);
    struct DataEntry* de_var1 = readDataEntry(agent);
    struct DataEntry* de_var2 = readDataEntry(agent);

    int16 val1 = GETE(de_var1,int16);
    int16 val2 = GETE(de_var2,int16);

    int16 ret = val1 / val2;

    PUTE(de_ret,ret,int16);
}



void EF_LHead(struct Agent_Var* agent)
{
    struct DataEntry* de_ret = readDataEntry(agent);
    struct DataEntry* de_op = readDataEntry(agent);

    addr_t dest_addr = getDataAddr(de_ret);
    addr_t src_addr = getDataAddr(de_op);

    src_addr += sizeof(dtype_t) + sizeof(list_size_t);

    memcpy((void*)dest_addr, (void*)src_addr, tavm_data_type_size[de_ret->type]);
}
void EF_LTail(struct Agent_Var* agent)
{
    struct DataEntry* de_dest = readDataEntry(agent);
    struct DataEntry* de_src = readDataEntry(agent);

    addr_t dest_addr = getDataAddr(de_dest);
    addr_t src_addr = getDataAddr(de_src);

    src_addr += sizeof(dtype_t)+ sizeof(list_size_t);;
    dest_addr += sizeof(dtype_t) + sizeof(list_size_t);

    list_size_t size = GET(de_src->pos+sizeof(dtype_t),de_src->tid,list_size_t);
    PUT(de_dest->pos+sizeof(dtype_t), de_dest->tid, size-1,list_size_t);

    dtype_t elemType = GETE(de_dest,dtype_t);

    memcpy((void*)dest_addr,(void*)(src_addr+tavm_data_type_size[elemType]), tavm_data_type_size[elemType]*(size-1));


}

void EF_LLink(struct Agent_Var* agent)
{
    struct DataEntry* de_dest = readDataEntry(agent);
    struct DataEntry* de_src = readDataEntry(agent);

    addr_t dest_addr = getDataAddr(de_dest);
    addr_t src_addr = getDataAddr(de_src);

    src_addr += sizeof(dtype_t)+ sizeof(list_size_t);;
    dest_addr += sizeof(dtype_t) + sizeof(list_size_t);

    list_size_t size1 = GET(de_src->pos+sizeof(dtype_t),de_src->tid,list_size_t);
    list_size_t size2 = GET(de_dest->pos+sizeof(dtype_t),de_dest->tid,list_size_t);
    PUT(de_dest->pos+sizeof(dtype_t), de_dest->tid, size1+size2,list_size_t);

    dtype_t elemType = GETE(de_dest,dtype_t);
    dest_addr += tavm_data_type_size[elemType]*size2;

    memcpy((void*)dest_addr,(void*)(src_addr), tavm_data_type_size[elemType]*(size1));
}

void EF_LAdd(struct Agent_Var* agent)
{
    struct DataEntry* de_dest = readDataEntry(agent);
    struct DataEntry* de_src = readDataEntry(agent);

    dtype_t elemType = GETE(de_dest,dtype_t);
    list_size_t size = GET(de_dest->pos+sizeof(dtype_t),de_dest->tid, list_size_t);
    PUT(de_dest->pos+sizeof(dtype_t),de_dest->tid,size+1,list_size_t);

    pos_t offset = sizeof(dtype_t)+sizeof(list_size_t)+size*tavm_data_type_size[elemType];

    MEMCPY(de_dest->pos+offset,de_dest->tid,de_src->pos,de_src->tid,tavm_data_type_size[elemType]);
}
